import { HOST, PASSWORD, USERNAME } from '../common/constants';
import { waitForGlobalLoading } from './loading';
import { getInput } from './xPath';
import { gcy, gcyAdvanced } from './shared';
import {
  deleteUserSql,
  enableEmailVerification,
  enableRegistration,
} from './apiCalls/common';

const loginWithFakeThirdPartyService = (
  service: string,
  username: string,
  redirectUrlPattern: string,
  redirectUrlOrigin: string,
  loginButtonGcy: DataCy.Value,
  responseType: boolean,
  scope: string,
  state: boolean
) => {
  waitForGlobalLoading();

  cy.intercept(redirectUrlPattern, {
    statusCode: 200,
    body: 'Fake third party auth',
  }).as('authRedirect');
  gcyAdvanced({ value: loginButtonGcy, provider: service })
    .should('be.visible')
    .click();

  return cy.wait('@authRedirect').then((interception) => {
    const params = new URL(interception.request.url).searchParams;
    expect(params.get('client_id')).to.eq('dummy_client_id');
    if (responseType) {
      expect(params.get('response_type')).to.eq('code');
    }
    expect(params.get('scope')).to.eq(scope);
    if (state) {
      expect(params.get('state')).to.matches(
        /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i
      ); // should be the uuid generated by crypto
    }

    cy.origin(redirectUrlOrigin, () => {
      cy.contains('Fake third party auth').should('be.visible');
    });
    let url = `${HOST}/login/auth_callback/${service}`;
    url += `?code=this_is_dummy_code_${username}`;
    if (state) {
      url += `&state=${params.get('state')}`;
    }
    cy.visit(url);
    waitForGlobalLoading();
  });
};

export const loginWithFakeGithub = (
  username: string,
  loginButtonGcy: DataCy.Value = 'login-provider'
) => {
  return loginWithFakeThirdPartyService(
    'github',
    username,
    'https://github.com/login/oauth/**',
    'https://github.com',
    loginButtonGcy,
    false,
    'user:email',
    false
  );
};

export const loginWithFakeGoogle = (
  username: string,
  loginButtonGcy: DataCy.Value = 'login-provider'
) => {
  return loginWithFakeThirdPartyService(
    'google',
    username,
    'https://accounts.google.com/o/oauth2/v2/**',
    'https://accounts.google.com',
    loginButtonGcy,
    true,
    'openid email https://www.googleapis.com/auth/userinfo.profile',
    false
  );
};

export const loginWithFakeOAuth2 = (
  username: string,
  loginButtonGcy: DataCy.Value = 'login-provider'
) => {
  return loginWithFakeThirdPartyService(
    'oauth2',
    username,
    'https://dummy-url.com/**',
    'https://dummy-url.com',
    loginButtonGcy,
    true,
    'openid email profile',
    true
  );
};

export const loginWithFakeSso = (
  username: string,
  loginButtonGcy: DataCy.Value = 'login-provider'
) => {
  return loginWithFakeThirdPartyService(
    'sso',
    username,
    'https://dummy-url.com/**',
    'https://dummy-url.com',
    loginButtonGcy,
    true,
    'openid profile email offline_access',
    true
  );
};

export const loginWithFake = (
  service: 'github' | 'google' | 'oauth2' | 'sso',
  username: string,
  loginButtonGcy: DataCy.Value = 'login-provider'
) => {
  switch (service) {
    case 'github':
      loginWithFakeGithub(username, loginButtonGcy);
      break;
    case 'google':
      loginWithFakeGoogle(username, loginButtonGcy);
      break;
    case 'oauth2':
      loginWithFakeOAuth2(username, loginButtonGcy);
      break;
    case 'sso':
      loginWithFakeSso(username, loginButtonGcy);
      break;
  }
};

export const loginViaForm = (username = USERNAME, password = PASSWORD) => {
  cy.xpath('//input[@name="username"]')
    .type(username)
    .should('have.value', username);
  cy.xpath('//input[@name="password"]')
    .type(password)
    .should('have.value', password);
  cy.gcy('login-button').click();
  return waitForGlobalLoading();
};

export const visitSignUp = () => cy.visit(HOST + '/sign_up');

export const fillAndSubmitSignUpForm = (
  username: string,
  withOrganization = true
) => {
  cy.waitForDom();
  cy.xpath(getInput('name')).should('be.visible').type('Test user');
  cy.xpath(getInput('email')).type(username);
  if (withOrganization) {
    cy.xpath(getInput('organizationName')).type('organization');
  }
  cy.xpath(getInput('password')).type('very.strong.password');
  gcy('sign-up-submit-button').click();
};

export const signUpAfter = (username: string) => {
  enableEmailVerification();
  enableRegistration();
  deleteUserSql(username);
};

export function checkAnonymousIdUnset() {
  cy.wrap(localStorage).invoke('getItem', 'anonymousUserId').should('be.null');
}

export function checkAnonymousIdSet() {
  cy.intercept('POST', '/v2/public/business-events/identify').as('identify');
  cy.wrap(localStorage)
    .invoke('getItem', 'anonymousUserId')
    .should('have.length', 36);
}

export function checkAnonymousUserIdentified() {
  cy.wait('@identify').its('response.statusCode').should('eq', 200);
}
